[Payment due @mkhutornyi] Allow clearing the Default Vendor by re-selecting it (CC/DC export only)#96227
Conversation
Tapping the currently-selected vendor on any accounting integration's Default Vendor selector now clears it. Previously the guarded update call skipped this case, leaving no path to unset the field from the UI. QBO and QBD send CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE; Sage Intacct, Certinia, and NetSuite send an empty string. Fixes Expensify/Expensify#659748
|
@Eskalifer1 Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
|
@codex review |
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
Hi @Beamanator, let me know when this is ready for review, thank you! |
|
Sounds good @Eskalifer1 - actually this requires being added to the |
|
Oh, i hadn't done it before. Feel free to reassign. Thank you! |
|
Thanks for the quick response @Eskalifer1 , and thanks @mkhutornyi for volunteering to take over! |
trjExpensify
left a comment
There was a problem hiding this comment.
Hm, not sure about this. For export with vendor bills, you must have a vendor chosen for export. So I don't know why we'd let you deselect a vendor to have no vendor selected. CC: @heyjennahay
|
minnnnteresting - @trjExpensify i'll tag you in slack here :D https://expensify.slack.com/archives/C03TME82F/p1784118449309309 |
| if (row.value !== nonReimbursableBillDefaultVendor) { | ||
| updateQuickbooksDesktopNonReimbursableBillDefaultVendor(policyID, row.value, nonReimbursableBillDefaultVendor); | ||
| } | ||
| const newValue = row.value === nonReimbursableBillDefaultVendor ? (CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE as string) : row.value; |
There was a problem hiding this comment.
as string cast here looks unnecessary.
|
@mkhutornyi i'm so sorry, i just asked you to review but can you pause reviewing this one for now? Just will we get @trjExpensify 's comment(s) sorted 🙏 [we're discussing in slack] |
|
🤖 Reviewed the diff. The change is clean, minimal, and correctly scoped to the CC/DC export paths. One backend item to confirm before merge, plus a minor consistency nit. ✅ Looks good
|
|
@codex review |
|
Codex Review: Didn't find any major issues. Nice work! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
Ok I believe we're good to go here now @mkhutornyi 🙏 (ready for another review) |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppandroid.movAndroid: mWeb ChromeiOS: HybridAppios.moviOS: mWeb SafariMacOS: Chrome / Safariweb.mov |
|
@mjasikowski Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
|
🎯 @mkhutornyi, thanks for reviewing and testing this PR! 🎉 A payment issue will be created for your review once this PR is deployed to production. If payment is not needed (e.g., regression PR review fix etc), react with 👎 to this comment to prevent the payment issue from being created. |
|
@mjasikowski back to you! |
|
🚧 Beamanator has triggered a test Expensify/App build. You can view the workflow run here. |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/Beamanator in version: 9.4.41-0 🚀
|
|
🤖 I reviewed the changes in this PR against the help site articles under Why: This PR adds a single, narrow interaction affordance — re-tapping the currently-selected Default Vendor clears it — gated to the CC/DC / Credit Card Charge export paths only (QBO The existing help articles describe Default Vendor only at the configuration level and don't document a clear/reset mechanism at all, so nothing in them is now inaccurate:
Documenting a path-specific micro-interaction (tap-again-to-clear on CC/DC, but a no-op on the Vendor Bill path) would add confusion rather than clarity, and per the PR description this is part of the broader, not-yet-released Vendor Matching for CC Expenses beta — the feature itself isn't documented on the help site yet. When that project ships, the clearing behavior can be folded into a single article update alongside the rest of the vendor-matching docs. Since no changes are needed, I have not created a draft docs PR. @Beamanator — if you'd like a docs PR anyway (e.g. to add a "clearing the default vendor" note now, or to pre-stage the broader vendor-matching docs), reply and I'll create one. |
|
worked well in staging for me! |
|
🤖 Payment issue created: #96707 |
|
🚀 Deployed to production by https://github.com/yuwenmemon in version: 9.4.41-4 🚀
Bundle Size Analysis (Sentry): |

Explanation of Change
On accounting integrations where the non-reimbursable export destination is Credit Card / Debit Card, blank Default Vendor has a defined UX — expenses without a vendor export to "Credit Card Misc". But once a Default Vendor is set on those export paths, there's no way to clear it: tapping the currently-selected row is a silent no-op that just navigates back. This blocks vendor-matching CC beta testers who need to reset workspaces between test scenarios.
This change lets the user re-tap the currently-selected vendor to clear it, but only on the CC/DC export paths:
QuickbooksNonReimbursableVendorSelectPage: gated onconfigKey === 'nonReimbursableCreditCardDefaultVendor'. The Bill entry point of the same shared page keeps its existing behavior.DynamicSageIntacctDefaultVendorPage: gated onsettingName === CONST.SAGE_INTACCT_CONFIG.NON_REIMBURSABLE_CREDIT_CARD_VENDOR. The Bill and reimbursable variants keep their existing behavior.Vendor Bill export paths are intentionally out of scope — blank on those integrations means "use the report submitter" and is set by disabling the parent Default Vendor toggle rather than by clearing the vendor from this list. QBD, NetSuite, and Certinia only support Vendor Bill export, so they're not touched.
Xero doesn't have a Default Vendor selector today; it will be added as part of the broader vendor-matching project.
Backend paths verified end-to-end:
'NONE'fornonReimbursableCreditCardDefaultVendorhas an existing frontend precedent:DynamicQuickbooksCompanyCardExpenseAccountPage.tsx#L128-L135already sends theNONEsentinel to clear the bill default vendor.api.php:3361-3367:UpdateSageIntacctNonreimbursableExpensesCreditCardChargeExportDefaultVendorreads$_REQUEST['vendorID'] ?? ''and forwards toPolicyAPI::updateManyPolicyConnectionConfigurations— no validation.PolicyAPI::updateManyPolicyConnectionConfigurationsonly special-casesautoSync.enabled; passes everything else through to Auth — no validation.UpdateManyPolicyConnectionConfigurationsenforces JSON-type consistency between current and new value. This field is typedstringin Onyx and App only ever writes strings (real vendor ID or''), soSTRING → STRINGpasses the check. Persistence is a straightJSONB_PATCH— the empty string is stored as-is.Known limitation — OldDot's Intacct export view clears this field by writing JSON
null, not''. If a workspace previously cleared the vendor from OldDot, the stored value isnulland the NewDot clear (empty string) would fail Auth's type check with400 Current value and new value are using different types. In practice this is rare — OldDot doesn't support vendor matching, so anyone actively using the CC/DC vendor default is already on NewDot — but flagging it as a known edge case.Fixed Issues
$ https://github.com/Expensify/Expensify/issues/659748
PROPOSAL: https://github.com/Expensify/Expensify/issues/659748#issuecomment-4985966633
Tests
QBO — Credit Card export path:
QBO — Vendor Bill export path (regression check, should NOT toggle):
Sage Intacct — Credit Card Charge path:
Sage Intacct — Vendor Bill / Reimbursable paths (regression check, should NOT toggle):
Offline tests
QA Steps
Same as tests - tag me & @heyjennahay to perform these and the rest of the Vendor Matching for CC Expenses flows
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionmainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari